package org.supda.system.dao.impl;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.DefaultButtonModel;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import org.supda.system.dao.BaseDao;
import org.supda.system.entity.TUser;
import org.supda.system.util.DataTablePageUtil;
import org.supda.system.util.DateUtil;
import org.supda.system.util.PageUtil;
import org.supda.system.util.search.ArraySearch;
import org.supda.system.util.search.DateSearch;
import org.supda.system.util.search.FuzzySearch;

/**
 * 
 * @author supda
 * @Date 2016-12-15 上午11:36:59
 * 
 */
@Repository("BaseDao")
public class BaseDaoImpl<T> implements BaseDao<T> {
    
	 @Autowired
	private SessionFactory sessionFactory;

    protected Session getCurrentSession() {  
        return sessionFactory.getCurrentSession();  
    }
    
    public Serializable save(T o) {
        return this.getCurrentSession().save(o);
    }

    public void delete(T o) {
        this.getCurrentSession().delete(o);
    }

    public void update(T o) {
        this.getCurrentSession().update(o);
    }

    public void saveOrUpdate(T o) {
        this.getCurrentSession().saveOrUpdate(o);
    }

    @SuppressWarnings("unchecked")
	public List<T> find(String hql) {
        return this.getCurrentSession().createQuery(hql).list();
    }

    public List<T> find(String hql, Object[] param) {
        Query q = this.getCurrentSession().createQuery(hql);  
        if (param != null && param.length > 0) {  
            for (int i = 0; i < param.length; i++) {  
                q.setParameter(i, param[i]);  
            }  
        }  
        return q.list();
    }

    public List<T> find(String hql, List<Object> param) {
        Query q = this.getCurrentSession().createQuery(hql);  
        if (param != null && param.size() > 0) {  
            for (int i = 0; i < param.size(); i++) {  
                q.setParameter(i, param.get(i));  
            }  
        }  
        return q.list();
    }

    public List<T> find(String hql, Object[] param, Integer page, Integer rows) {
        if (page == null || page < 1) {  
            page = 1;  
        }  
        if (rows == null || rows < 1) {  
            rows = 10;  
        }  
        Query q = this.getCurrentSession().createQuery(hql);  
        if (param != null && param.length > 0) {  
            for (int i = 0; i < param.length; i++) {  
                q.setParameter(i, param[i]);  
            }  
        }  
        return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();  
    }
    
    public PageUtil listByPage(PageUtil page, T o) {
    	
        if (page == null ) {  
        	page = new PageUtil();
        }
        
        StringBuffer sb = new StringBuffer();
        
        sb.append("FROM ").append(o.getClass().getSimpleName());
        
        if(!StringUtils.isEmpty(page.getOrderBy()))
        	if(page.getAsc()){
        		sb.append(" order by ").append(page.getOrderBy());
        	}else{
        		sb.append(" order by ").append(page.getOrderBy()).append(" desc");}

        //System.out.println(sb.toString());
        
        Query q = this.getCurrentSession().createQuery(sb.toString());  
        
        //System.out.println(page);

        page.setRecords(q.setFirstResult((page.getCurrentPage() - 1) * page.getShowRecordNum()).setMaxResults(page.getShowRecordNum()).list());
        
        return page;
    }

    public List<T> find(String hql, List<Object> param, Integer page,
            Integer rows) {
        if (page == null || page < 1) {  
            page = 1;  
        }  
        if (rows == null || rows < 1) {  
            rows = 10;  
        }  
        Query q = this.getCurrentSession().createQuery(hql);  
        if (param != null && param.size() > 0) {  
            for (int i = 0; i < param.size(); i++) {  
                q.setParameter(i, param.get(i));  
            }  
        }  
        return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
    }

    public T get(Class<T> c, Serializable id) {
        return (T) this.getCurrentSession().get(c, id);
    }

    public T get(String hql, Object[] param) {
        List<T> l = this.find(hql, param);  
        if (l != null && l.size() > 0) {  
            return l.get(0);  
        } else {  
            return null;  
        }
    }

    public T get(String hql, List<Object> param) {
        List<T> l = this.find(hql, param);  
        if (l != null && l.size() > 0) {  
            return l.get(0);  
        } else {  
            return null;  
        }
    }

    public Long count(String hql) {
        return (Long) this.getCurrentSession().createQuery(hql).uniqueResult();
    }

    public Long count(String hql, Object[] param) {
        Query q = this.getCurrentSession().createQuery(hql);  
        if (param != null && param.length > 0) {  
            for (int i = 0; i < param.length; i++) {  
                q.setParameter(i, param[i]);  
            }  
        }  
        return (Long) q.uniqueResult();
    }

    public Long count(String hql, List<Object> param) {
        Query q = this.getCurrentSession().createQuery(hql);  
        if (param != null && param.size() > 0) {  
            for (int i = 0; i < param.size(); i++) {  
                q.setParameter(i, param.get(i));  
            }  
        }  
        return (Long) q.uniqueResult();
    }

    public Integer executeHql(String hql) {
        return this.getCurrentSession().createQuery(hql).executeUpdate();
    }

    public Integer executeHql(String hql, Object[] param) {
        Query q = this.getCurrentSession().createQuery(hql);  
        if (param != null && param.length > 0) {  
            for (int i = 0; i < param.length; i++) {  
                q.setParameter(i, param[i]);  
            }  
        }  
        return q.executeUpdate();  
    }

    public Integer executeHql(String hql, List<Object> param) {
        Query q = this.getCurrentSession().createQuery(hql);  
        if (param != null && param.size() > 0) {  
            for (int i = 0; i < param.size(); i++) {  
                q.setParameter(i, param.get(i));  
            }  
        }  
        return q.executeUpdate();
    }

	@Override
	public List<T> findByWhere(T o) throws Exception {
		Class clazz = o.getClass();
		
		Field[] fields = clazz.getDeclaredFields();
		Method[] methods = clazz.getDeclaredMethods();
		
		String tableName = clazz.getName();
		
		//拼出查询条件
		Map<String ,Object> params = new HashMap<String,Object>();
		
		for(Method method : methods){
			String methodName = method.getName();
			for(Field field : fields){
				String fieldName = field.getName();
				if(("get"+fieldName).toUpperCase().equals(methodName)){
						Object obj = method.invoke(o);
					if(obj!=null)
						params.put(fieldName, obj);
				}
			}
		}
		
		if(params.size()>0) {
		
			//查询条件
			StringBuffer wcon = new StringBuffer();
			Object[] param = new Object[params.size()];
			
			int index = 0;
			
			for(Iterator<Entry<String,Object>> it = params.entrySet().iterator();it.hasNext();)
			{
				Entry<String,Object> entry = it.next();
			
				String key = entry.getKey();
				Object value = entry.getValue();
				
				wcon.append(key);
				wcon.append(" = ? ");
				param[index++] = value;
			}
			
			return find("FROM "+tableName+" "+wcon, param);
		}
	
		throw new  RuntimeException("");
	}
	
	@Override
	public void listByDataTable(DataTablePageUtil<T> dtp ,Class<T> t) {
        
		//System.out.println(dtp);
		
        StringBuffer sb = new StringBuffer();
        //System.out.println("查询表:"+t.getSimpleName());
        sb.append(" FROM ").append(t.getSimpleName());
        
        LinkedList<Object> paramList = null;
        
        if((dtp.getCondition() != null && dtp.getCondition().size() > 0)
        		||dtp.getArraySearchs().size() > 0
        		||dtp.getDateSearchs().size() > 0
        		||dtp.getFuzzySearchs().size() > 0
        		) {
        
        	paramList = new LinkedList<Object>();
        	
        	String hql = null;
        	//参数封装成对象
        	try {
        		hql = paramsWarpToObject(t , paramList , dtp);
			} catch (Exception e) {
				throw new RuntimeException("参数异常");
			}

        	if(!StringUtils.isEmpty(hql)){
            	sb.append(" WHERE 1 = 1 ");
        	
            	if(hql.startsWith(" OR")){
            		hql = hql.replaceFirst(" OR", " AND");
            	}
            	sb.append(hql);

        	}
        }
        
        Query q = this.getCurrentSession().createQuery(sb.toString());  
        //总记录条数
        Query count = this.getCurrentSession().createQuery("SELECT COUNT(*) "+sb.toString());
        
        if (paramList != null && paramList.size() > 0) {  
            for (int i = 0; i < paramList.size(); i++) {  
                q.setParameter(i, paramList.get(i));  
                count.setParameter(i,  paramList.get(i));
            }  
        }  
        
        Object allNum = this.getCurrentSession().createQuery("SELECT COUNT(*) FROM "+t.getSimpleName()).uniqueResult();
        
        dtp.setRecordsFiltered(Integer.parseInt(count.uniqueResult()+""));
        
        dtp.setRecordsTotal(Integer.parseInt(allNum.toString()+""));
        
        //数据
        dtp.setData(q.setFirstResult(dtp.getStart()).setMaxResults(dtp.getLength()).list());
	}

	//拼接条件语句
	private String  paramsWarpToObject(Class<T> t ,LinkedList<Object> params ,  DataTablePageUtil<T> dtp) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, ParseException {

		Map<String , String> condition = null;
		StringBuffer hql = new StringBuffer();
		
		//condition封装
		condition = dtp.getCondition();
		
		if(dtp.getCondition()!=null && dtp.getCondition().size() > 0){
			for(Iterator<Entry<String, String>> it = condition.entrySet().iterator() ; it.hasNext() ; ){
				
				Entry<String, String> entry = it.next();
				String key = entry.getKey();
				String value = entry.getValue();

				warpTFiledObject(t, key, hql, params, "", false, false, new String[]{value});
			}
		}
		
		//fuzzySearch条件解析
		if(dtp.getFuzzySearchs()!=null && dtp.getFuzzySearchs().size()>0) {
			
			for(FuzzySearch fs: dtp.getFuzzySearchs()){
				for(String dataType : fs.getDatatype())
					warpTFiledObject(t, dataType, hql, params, "", true, true, new String[]{fs.getValue()});
			}
			
		}
		
		//dateSearchs条件解析
		if(dtp.getDateSearchs()!=null && dtp.getDateSearchs().size() > 0) {
		
			for(DateSearch ds: dtp.getDateSearchs()){
				warpTFiledObject(t, ds.getDatatype(), hql, params, ds.getPattern(), false, false, new String[]{ds.getDatemin(),ds.getDatemax()});
			}
		}
		
		//ArraySearchs条件解析
		if(dtp.getArraySearchs()!=null && dtp.getArraySearchs().size() > 0) {
			
			for(ArraySearch as: dtp.getArraySearchs()){
				//warpTFiledObject(t, as.getDatatype(), hql, params, false, as.getValue());
			}
		}
		
		return hql.toString();
	}
	
	/**
	 * 反射取出该类类型的数据
	 * @param value
	 * @param clazz
	 * @param field
	 * @return
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 * @throws ParseException 
	 */
	static <T> void warpTFiledObject(Class<T> t , String tfield , StringBuffer hql , LinkedList<Object> params , String pattern, boolean isOr, boolean fuzzy, String[] value) throws InstantiationException, IllegalAccessException, ParseException{
		
		T o = t.newInstance();
		Field[] fileds = t.getDeclaredFields();
		
		for(Field field : fileds){
			String fieldName = field.getName();
			//反射set赋值
			if(fieldName.equalsIgnoreCase(tfield)){
				Class<?> clazz = field.getType();
				
				//String参数转换
				Object param = null;
				
				//添加参数
				for(int i = 0 ; i < value.length ; i ++){
					param = StringToObject(value[i], clazz, pattern);
					
					if(param != null && !StringUtils.isEmpty(param.toString())){
						if(fuzzy)
							params.add("%"+param+"%");
						else
							params.add(param);
					}
				}
				
				if(param != null && !StringUtils.isEmpty(param.toString())){
					if(isOr)
						hql.append(" OR (");
					else
						hql.append(" AND (");
					
					hql.append(fieldName);
					
					if((clazz == Date.class || clazz == Timestamp.class)&&(value.length >= 2))
					{
						hql.append(" <= ? ");
						hql.append(" AND ");
						hql.append(fieldName);
						hql.append(" >= ?) ");
					}else if(fuzzy){
						hql.append(" like ?) ");
					}else{	
						hql.append(" = ?) ");
					}
				}
					
			}
		}
	}
	
	/**
	 * String 转指定类型
	 * @param value
	 * @param clazz
	 * @return
	 * @throws ParseException 
	 */
	static Object StringToObject(String value, Class<?> clazz, String pattern) throws ParseException {
		
		if(StringUtils.isEmpty(value)){
			return null;
		}
		
		if(clazz == Integer.class){
			return Integer.parseInt(value);
		}else if(clazz == String.class){
			return value;
		}else if(clazz == Timestamp.class){
			return DateUtil.parseToTimestamp(value, pattern);
		}else if(clazz == Boolean.class){
			return Boolean.parseBoolean(value);
		}else if(clazz == Double.class){
			return Double.parseDouble(value);
		}else if(clazz == Float.class){
			return Float.parseFloat(value);
		}else if(clazz == Date.class){
			return DateUtil.parse(value, pattern);
		}else if(clazz == Long.class){
			return Long.parseLong(value);
		}else if(clazz == Short.class){
			return Short.parseShort(value);
		}
		
		return null;
	}
	
	public static void main(String[] args) {
		//StringToObject("sds",Integer.class);
		Field[] fields = new TUser().getClass().getDeclaredFields();
		
		System.out.println(fields[4].getType());
		
	}
	
}